﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////


#pragma once
#include "GnufIAsynchronousTaskHandler.h"
#include "GcmpUiBase.h"

namespace {
    class AsynchronousTaskManagerImpl;
}

namespace gnuf {
    class IAsynchronousTaskHandler;

    class GCMP_UIBASE_EXPORT AsynchronousTask : public gcmp::WeakReferenceable
    {
    public:
        enum class EType : std::uint8_t
        {
            eDeferred,
            eThread
        };

        enum class ESubtype : std::uint32_t
        {
            eDefault = 0
        };

        AsynchronousTask(
            AsynchronousTask::EType,
            AsynchronousTask::ESubtype,
            IAsynchronousTaskHandler * pHandler);
        virtual ~AsynchronousTask();

        // Return false if not workable. This means that you cannot depend on
        // the Asynchronous Task System to execute any task (e.g. submit and 
        // then wait to execute).
        static bool workable();

        // Register the subtype. The hint provided will be used if it is available,
        // otherwise it will return a value that has not yet been registered.
        static AsynchronousTask::ESubtype registerSubtype(
            AsynchronousTask::ESubtype hint = AsynchronousTask::ESubtype::eDefault);

        // Return the type.
        const AsynchronousTask::EType type() const { return m_type; }

        // Return the subtype.
        AsynchronousTask::ESubtype subtype() const { return m_subtype; }
        
        // Set/Get the handler that handles this task.
        void setHandler(IAsynchronousTaskHandler *);
        const IAsynchronousTaskHandler * handler() const;

        // Submit a task. Note that, once submitted, this task's ownership will
        // transfer to the global AsynchronousTaskManager instance!
        static void submit(gcmp::OwnerPtr< AsynchronousTask > &&);

        // Submit this task. Note that, once submitted, this task's ownership will
        // transfer to the global AsynchronousTaskManager instance!
        void submit();

        // Return true if submitted. Otherwise, return false.
        bool isSubmitted() const { return m_submitted; }

        // Execute this task.
        virtual void execute() = 0;

        // Return true during executing.
        virtual bool isExecuting() const = 0;

        // Return true if the same type.
        bool isTheSameTypeAs(const AsynchronousTask * pThat) const
        {
            return (
                nullptr != pThat &&
                type() == pThat->type() &&
                subtype() == pThat->subtype() &&
                onIsTheSameTypeAs(pThat));
        }

    protected:
        // Give the derived class an opportunity to check if the same type as that.
        virtual bool onIsTheSameTypeAs(const AsynchronousTask * pThat) const { return true; }

        // Unsubmit this task and return the ownership if submitted successfully.
        gcmp::OwnerPtr<AsynchronousTask> unsubmit();

        IAsynchronousTaskHandler * handler();
        
    private:
        friend class ::AsynchronousTaskManagerImpl;
        void setSubmitted(bool);

        const AsynchronousTask::EType m_type;
        const AsynchronousTask::ESubtype m_subtype;
        gcmp::WeakPtr< IAsynchronousTaskHandler > m_wpHandler;
        bool m_submitted;
    };

    class GCMP_UIBASE_EXPORT AsynchronousTaskManager final
    {
    public:
        AsynchronousTaskManager();
        ~AsynchronousTaskManager();

        static AsynchronousTaskManager * get();

        AsynchronousTaskManagerImpl * impl() { return m_impl.get(); }
        const AsynchronousTaskManagerImpl * impl() const { return m_impl.get(); }

    private:
        gcmp::OwnerPtr< AsynchronousTaskManagerImpl > m_impl;
    };

    class GCMP_UIBASE_EXPORT LockAsynchronousTask final
    {
    public:
        LockAsynchronousTask(const LockAsynchronousTask &)              = delete;   // 禁用拷贝构造
        LockAsynchronousTask(LockAsynchronousTask &&)                   = delete;   // 禁用右值引用构造
        LockAsynchronousTask & operator=(const LockAsynchronousTask &)  = delete;   // 禁用拷贝赋值

        /// \brief 构造时，锁住AsynchronousTask。禁止AsynchronousTask执行。
        explicit LockAsynchronousTask();
        /// \brief 析构时，解锁AsynchronousTask。允许AsynchronousTask执行。
        ~LockAsynchronousTask();

        /// \return 返回true，如果被Locked。
        static bool isLocked();

    private:
        static std::uint16_t s_countLocked; // range: 0~65535
        bool m_valid = false;               // invalid, by default
    };
}
